﻿using Microsoft.AspNetCore.Mvc;
using System.Reflection;

namespace Rj.PersonnelVerification.Server.Extensions
{
    public static class ServiceCollectionExtensions
    {
        public static IServiceCollection AddScopedFromNamespace(
        this IServiceCollection services,
        string namespaceName,
        params Assembly[] assemblies)
        {
            foreach (Assembly assembly in assemblies)
            {
                var types = assembly
                    .GetTypes()
                    .Where(x =>
                        x.IsClass && x.Namespace != null && !x.IsAbstract && !x.IsInterface && x.BaseType != typeof(ControllerBase)
                        && !Attribute.IsDefined(x, typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute))
                        && x.Namespace!.StartsWith(namespaceName, StringComparison.InvariantCultureIgnoreCase)
                    ).Select(t => new { Service=t.GetInterfaces().FirstOrDefault(), Implementation =t}).Where(t=>t.Service!=null);

                foreach (var type in types)
                {
                    if (services.All(x => x.ServiceType != type.Service))
                    {
                        _ = services.AddScoped(type.Service,type.Implementation);
                    }
                }
            }

            return services;
        }

        public static IServiceCollection AddSingletonFromNamespace(
        this IServiceCollection services,
        string namespaceName,
        params Assembly[] assemblies)
        {
            foreach (Assembly assembly in assemblies)
            {
                var types = assembly
                    .GetTypes()
                    .Where(x =>
                        x.IsClass && x.Namespace != null && !x.IsAbstract && !x.IsInterface && x.BaseType != typeof(ControllerBase)
                        && !Attribute.IsDefined(x, typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute))
                        && x.Namespace!.StartsWith(namespaceName, StringComparison.InvariantCultureIgnoreCase)
                    ).Select(t => new { Service = t.GetInterfaces().FirstOrDefault(), Implementation = t }).Where(t => t.Service != null);

                foreach (var type in types)
                {
                    if (services.All(x => x.ServiceType != type.Service))
                    {
                        _ = services.AddSingleton(type.Service, type.Implementation);
                    }
                }
            }

            return services;
        }
        public static IServiceCollection AddTransientFromNamespace(
        this IServiceCollection services,
        string namespaceName,
        params Assembly[] assemblies)
        {
            foreach (Assembly assembly in assemblies)
            {
                IEnumerable<Type> types = assembly
                    .GetTypes()
                    .Where(x =>
                        x.IsClass && x.Namespace != null && !x.IsAbstract && !x.IsInterface && x.BaseType != typeof(ControllerBase)
                        && x.Namespace!.StartsWith(namespaceName, StringComparison.InvariantCultureIgnoreCase)
                    );

                foreach (Type? type in types)
                {
                    if (services.All(x => x.ServiceType != type))
                    {
                        _ = services.AddTransient(type);
                    }
                }
            }

            return services;
        }
    }
}
